You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Problem:
The useRemoteConnection hook stored the WebSocket instance using useState. The useEffect cleanup function captured the initial state value (null) via closure, so ws?.close() on unmount never actually closed the real socket. This caused:
Zombie WebSocket connections that stayed open after navigating away
Pending reconnect timers firing after the component was gone
WebSocket is closed before the connection is established browser warnings during navigation (React Strict Mode double-mounting) Fix useRemoteConnection.ts :
Replaced useState<WebSocket> with useRef<WebSocket> so cleanup always accesses the current socket
Added an isMounted flag to prevent reconnection attempts after unmount
Deferred initial socket creation with setTimeout(connect, 0) to avoid creating sockets during React Strict Mode's instant unmount cycle
Nullified event handlers (onopen, onclose, onerror before calling .close() to prevent cascading error events
Stabilized send and sendCombo callbacks with empty dependency arrays since ref identity never changes
Checklist
My PR addresses a single issue, fixes a single bug or makes a single improvement.
My code follows the project's code style and conventions
If applicable, I have made corresponding changes or additions to the documentation
If applicable, I have made corresponding changes or additions to tests
My changes generate no new warnings or errors
I have joined the Discord server and I will share a link to this PR with the project maintainers there
Fixed a WebSocket lifecycle bug in useRemoteConnection.ts by replacing state-based management with ref-based storage, introducing an isMounted guard to prevent post-unmount actions, ensuring sockets close properly, and improving cleanup logic to eliminate zombie connections.
Converted WebSocket from useState to useRef (wsRef), added isMounted guard to prevent reconnection after unmount, debounced initial connection with 0ms timer, forcibly closes existing sockets before new connections, improved cleanup to safely clear timers and detach handlers, updated send operations to use wsRef.current.
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
🐰 A socket that lingered, long after its day,
Haunting the server in zombie's own way,
But refs hold their truth where state fades to dust,
A mounted guard watches—now closures we trust!
No phantom connections shall roam anymore, hop!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #80
Problem:
The useRemoteConnection hook stored the WebSocket instance using
useState. TheuseEffectcleanup function captured the initial state value (null) via closure, sows?.close()on unmount never actually closed the real socket. This caused:WebSocket is closed before the connection is establishedbrowser warnings during navigation (React Strict Mode double-mounting)Fix useRemoteConnection.ts :
useState<WebSocket>withuseRef<WebSocket>so cleanup always accesses the current socketisMountedflag to prevent reconnection attempts after unmountsetTimeout(connect, 0)to avoid creating sockets during React Strict Mode's instant unmount cycle.close()to prevent cascading error eventssendandsendCombocallbacks with empty dependency arrays since ref identity never changesChecklist